namespace Brjnk.Maps
{
    using System;
    using System.ComponentModel;
    using System.Threading;

    public class ScheduledAction : IScheduledAction, System.ComponentModel.INotifyPropertyChanged
    {
        private Delegate action;
        private object[] args;
        private SynchronizationContext context;

        public ScheduledAction(Delegate action, object[] args, SynchronizationContext context)
        {
            this.action = action;
            this.args = args;
            this.context = context;
        }

        public ScheduledAction(Delegate action, SynchronizationContext context) :
            this(action, null, context) { }

        public void Execute(TicksTime time)
        {
            if (context == null) action.DynamicInvoke(args);
            else { context.Post(new SendOrPostCallback(state => action.DynamicInvoke(args)), null); }
        }

        private bool progressRequired;

        public bool ProgressRequired
        {
            get { return progressRequired; }
            set { progressRequired = value; OnPropertyChanged("ProgressRequired"); }
        }

        private TimeSpan remainingTime;

        public TimeSpan RemainingTime
        {
            get { return remainingTime; }
            protected set { remainingTime = value; OnPropertyChanged("RemainingTime"); }
        }

        private TicksTime startTime;

        public TicksTime StartTime
        {
            get { return startTime; }
            protected set { startTime = value; OnPropertyChanged("StartTime"); }
        }

        private TicksTime endTime;

        public TicksTime EndTime
        {
            get { return endTime; }
            protected set { endTime = value; OnPropertyChanged("EndTime"); }
        }

        public void UpdateProgress(TimeSpan remainingTime)
        {
            this.remainingTime = remainingTime;
        }

        public void Reset(TicksTime startTime, TicksTime endTime)
        {
            StartTime = startTime;
            EndTime = endTime;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                if (context != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                else context.Post(new SendOrPostCallback(state => PropertyChanged(this, new PropertyChangedEventArgs(propertyName))), null);
            }
        }
    }
}